package utils

/***
  fifo queue
*/

import "sync"

type SyncQueue struct {
	lock  *sync.RWMutex
	dlist *DLinklist
}

func NewSyncQueue() *SyncQueue {
	rval := &SyncQueue{
		lock:  new(sync.RWMutex),
		dlist: NewDlinklist(),
	}
	return rval
}

func (this *SyncQueue) Count() int32 {
	this.lock.RLock()
	defer this.lock.RUnlock()
	return this.dlist.cnt
}

func (this *SyncQueue) Reset() {
	this.lock.Lock()
	defer this.lock.Unlock()
	for {
		node := this.dlist.RemoveFirst()
		if node != nil {
			node.Value = nil
			node.release2Pool() // 归还node
		}
		if node == nil {
			break
		}
	}
}

func (this *SyncQueue) Push(val interface{}) {
	node := NewDlinknodeFromPool()
	node.Value = val
	this.lock.Lock()
	defer this.lock.Unlock()
	this.dlist.Append(node)
}

/**
 * Peek第一个
 */
func (this *SyncQueue) Peek() (bool, interface{}) {
	this.lock.RLock()
	defer this.lock.RUnlock()
	node := this.dlist.SeekFirst()
	if node != nil {
		rval := node.Value // 暂存
		return true, rval
	} else {
		return false, nil
	}
}

/**
 * 弹出第一个
 */
func (this *SyncQueue) Pop() (bool, interface{}) {
	this.lock.Lock()
	defer this.lock.Unlock()
	node := this.dlist.RemoveFirst()
	if node != nil {
		rval := node.Value // 暂存
		node.Value = nil
		node.release2Pool() // 归还node
		return true, rval
	} else {
		return false, nil
	}
}

/**
 * 取多个任务, 一般在回调中执行
 */
func (this *SyncQueue) PopTaskArgMaxFunc(max int, cb func(args interface{}) bool) int {
	i := 0
	for i < max {
		if ok, val := this.Pop(); ok {
			i++
			if !cb(val) {
				break
			}
		} else {
			break
		}
	}
	return i
}

/*
**

	先获取所有的节点后, 再进行遍历, 避免产生死锁
*/
func (this *SyncQueue) Range(cb func(idx int, value interface{}, removeit *bool) bool) {
	this.lock.RLock()
	lst := this.dlist.Nodes()
	this.lock.RUnlock()
	removeit := false
	for i := 0; i < len(lst); i++ {
		removeit = false
		node := lst[i]
		ret := cb(i, node.Value, &removeit)
		if removeit {
			this.lock.Lock()
			if this.dlist.Remove(node) {
				node.Value = nil
				node.release2Pool()
			}
			this.lock.Unlock()
		}
		if !ret {
			break
		}
	}
}
